import path from 'path';
import fs from 'fs-extra';
import store from './store';
import sqlite from '~sqlite';
import hotkey from '~hotkey';
import jsonfile from 'jsonfile';
import win32Def from '~win32/def';
import win32Sdk from '~win32/sdk';
import { execaCommand } from 'execa';
import buildInCommand from '~command';
import windowsNative from '~win32/module/windows';
import clipboardNative from '~win32/module/clipboard';
import { IpcMainEventEnum, IpcRendererEventEnum } from '~common/enum';
import { clipboard, ipcMain, BrowserWindow, dialog, OpenDialogSyncOptions, shell } from 'electron';

type TProperties = OpenDialogSyncOptions['properties'];

let hasOnEvent = false;
const isWindows = store.state.isWindows;

/**
 * 激活上一个窗口
 */
function activatePrevWindow() {
    if (isWindows) {
        const prevActiveWindowHandle = store.state.prevActiveWindowHandle;
        store.clearPrevActiveHandle();
        if (typeof prevActiveWindowHandle === 'number') {
            win32Sdk.SwitchToThisWindow(prevActiveWindowHandle, true);
        }
    } else {
        hotkey.activatePrevWindow();
    }
}

/**
 * 挂载 Window 消息，监听主进程事件
 */
export async function winEventHooks(window: BrowserWindow): Promise<void> {
    // 每次创建窗口都会调用一次该方法，
    // 导致监听的回调会被多次执行，因此需要做拦截
    if (hasOnEvent) {
        return;
    } else {
        hasOnEvent = true;
    }

    const windowState = store.getWindowState(window.getTitle());
    if (windowState) {
        if (windowState.hasBindHooks) {
            return;
        } else {
            store.setWindowState(window.getTitle(), { hasBindHooks: true });
        }
    }

    bindCopidEvent(window);

    // 隐藏窗口
    ipcMain.on(IpcMainEventEnum.HIDE_WINDOWS, () => {
        store.state.currentActiveWindow?.hide();
    });

    // 退到后台，并激活上一个活跃窗口
    ipcMain.on(IpcMainEventEnum.BACKEND_WINDOWS, () => {
        activatePrevWindow();
        store.state.currentActiveWindow?.hide();
    });

    // 退到后台，并激活上一个活跃窗口后粘贴
    ipcMain.on(IpcMainEventEnum.BACKEND_WINDOWS_AND_PASTE, () => {
        if (isWindows) {
            const prevActiveWindowHandle = store.state.prevActiveWindowHandle;
            store.clearPrevActiveHandle();
            if (typeof prevActiveWindowHandle === 'number') {
                win32Sdk.SwitchToThisWindow(prevActiveWindowHandle, true);
                setTimeout(() => {
                    windowsNative.virtualKeyPaste();
                }, 400);
            }
        } else {
            hotkey.activatePrevWindow();
            setTimeout(() => {
                hotkey.virtualKeyPaste();
            }, 400);
        }
        store.state.currentActiveWindow?.hide();
    });

    // 打开目录对话框
    ipcMain.on(IpcMainEventEnum.OPEN_DIALOG, (_, args) => {
        const { type, openPath } = args || {};

        const properties: TProperties = ['multiSelections'];
        const options: OpenDialogSyncOptions = {};

        switch (type) {
            case 'selectFile':
                properties.push('openFile');
                break;
            case 'selectDir':
                properties.push('openDirectory');
                break;
        }

        options.properties = properties;
        openPath && (options.defaultPath = openPath);

        const result = dialog.showOpenDialogSync(options);
        store.state.currentActiveWindow?.webContents.send(IpcRendererEventEnum.OPEN_DIALOG_RESULT, { isCancel: !result, paths: result });
    });

    // 打开目录或文件位置
    ipcMain.on(IpcMainEventEnum.OPEN_FOLDER, (_, args) => {
        const { path } = args || {};
        if (path) {
            shell.showItemInFolder(path);
        }
    });

    // 写入 JSON
    ipcMain.on(IpcMainEventEnum.WRITE_JSON, (_, args) => {
        const { content, filepath } = args;
        jsonfile.writeFileSync(filepath, content, { spaces: 4, EOL: '\r\n' });
    });

    // 读取文件内容
    ipcMain.on(IpcMainEventEnum.READ_FILE, (_, args) => {
        const { filepath } = args;
        const content = fs.readFileSync(filepath, 'utf-8');
        store.state.currentActiveWindow?.webContents.send(IpcRendererEventEnum.READ_FILE_RESULT, { content });
    });

    // 执行命令
    ipcMain.on(IpcMainEventEnum.RUN_COMMANDS, async (_, args) => {
        try {
            let { commands, cwd, async } = args || {};
            if (Array.isArray(commands)) {
                commands = commands.filter((c: string) => {
                    c = c.trim();
                    return c && !c.startsWith('#');
                });
                if (async) {
                    const promises = commands.map((c: string) => {
                        return new Promise(resolve => {
                            if (buildInCommand.isBuildInCommand(c)) {
                                buildInCommand.context
                                    .exec(c)
                                    .then(ret => {
                                        resolve({ command: c, stdout: ret });
                                    })
                                    .catch(err => {
                                        resolve({ command: c, stderr: err });
                                    });
                            } else {
                                execaCommand(c, { cwd: cwd || process.cwd() })
                                    .then(result => {
                                        resolve({ command: c, stdout: result.stdout });
                                    })
                                    .catch(err => {
                                        resolve({ command: c, stderr: err });
                                    });
                            }
                        });
                    });
                    Promise.all(promises).then(results => {
                        store.state.currentActiveWindow?.webContents.send(IpcRendererEventEnum.RUN_COMMANDS_FINISH, results);
                    });
                } else {
                    const results = [];
                    for (const c of commands) {
                        try {
                            if (buildInCommand.isBuildInCommand(c)) {
                                const result = await buildInCommand.context.exec(c);
                                results.push({ command: c, stdout: result });
                            } else {
                                const result = await execaCommand(c, {
                                    cwd: cwd || process.cwd(),
                                });
                                results.push({ command: c, stdout: result.stdout });
                            }
                        } catch (err) {
                            results.push({ command: c, stderr: err });
                            break;
                        }
                    }
                    store.state.currentActiveWindow?.webContents.send(IpcRendererEventEnum.RUN_COMMANDS_FINISH, results);
                }
            }
        } catch (error) {
            console.error(error);
            store.state.currentActiveWindow?.webContents.send(IpcRendererEventEnum.RUN_COMMANDS_ERROR, error);
        }
    });

    // 执行脚本
    ipcMain.on(IpcMainEventEnum.EXEC_SCRIPT, async (_, args) => {
        try {
            const { scriptContent, cwd } = args || {};
            const scriptFileName = '_runscript_.js';
            const scriptFilePath = path.join(cwd || process.cwd(), scriptFileName);
            fs.writeFileSync(scriptFilePath, scriptContent);

            let result;
            try {
                const r = await execaCommand(`node ${scriptFileName}`, { cwd: cwd || process.cwd() });
                result = { stdout: r.stdout };
            } catch (error) {
                result = { stderr: error };
            }

            fs.removeSync(scriptFilePath);
            store.state.currentActiveWindow?.webContents.send(IpcRendererEventEnum.EXEC_SCRIPT_FINISH, result);
        } catch (error) {
            console.error(error);
            store.state.currentActiveWindow?.webContents.send(IpcRendererEventEnum.EXEC_SCRIPT_ERROR, error);
        }
    });
}

/**
 * Copid 业务事件
 */
function bindCopidEvent(window: BrowserWindow) {
    // ...
    const createClipboardRecord = (content: string) => {
        sqlite.clipboard.createOne({ content }, { deleteSameRecord: true }).then(resolveInfo => {
            if (resolveInfo.data) {
                if (store.state.copidRecord.clipboardDataQueue.length < store.state.copidRecord.queueMaxSize) {
                    store.state.copidRecord.clipboardDataQueue.push({ content: resolveInfo.data.content });
                }
                window.webContents.send(IpcRendererEventEnum.CLIPBOARD_UPDATE, { clipboard: resolveInfo });
            }
        });
    };

    if (isWindows) {
        try {
            // 添加剪贴板监听器
            const windowHandle = win32Sdk.FindWindowA(null, 'Copid');
            if (windowHandle) {
                // @ts-ignore
                clipboardNative.addClipboardFormatListenerByWinHandle(windowHandle);
            }

            // 剪贴板内容监听
            if (window.getTitle() === 'Copid') {
                window.hookWindowMessage(win32Def.WM_CLIPBOARDUPDATE, () => {
                    const content = clipboard.readText().trim();
                    if (content) createClipboardRecord(content);
                });
            }
        } catch (error) {
            console.error(error);
        }

        // ...
    } else {
        let timer: NodeJS.Timer | null = null;
        let prevContent = clipboard.readText().trim();
        try {
            // 轮询监听剪贴板
            timer = setInterval(() => {
                const currContent = clipboard.readText().trim();
                if (currContent && currContent !== prevContent) {
                    prevContent = currContent;
                    createClipboardRecord(currContent);
                }
            }, 1500);
        } catch (error) {
            console.error(error);
            if (timer) clearInterval(timer);
        }
    }
}
